import { computed } from 'vue'
import { get } from '../core/utils'
import { merge } from 'lodash-es'
import { request } from '../useRequest'

import type { Service } from '../core/types'
import type { PaginationOptions, PaginationFetchResult } from './types'

export const pagination = <Data, P extends unknown[] = any[]>(
  service: Service<Data, P>,
  options: PaginationOptions<Data, P> = {}
): PaginationFetchResult<Data, P> => {
  const defaultPaginationOptions = {
    currentKey: 'nowPage',
    pageSizeKey: 'pageSize',
    totalKey: 'result.total',
    totalPageKey: 'result.pages'
  }

  const { pagination, ...otherOptions } = options

  const { currentKey, pageSizeKey, totalKey, totalPageKey } = merge(defaultPaginationOptions, pagination)

  const finallyOptions = merge({ defaultParams: [{ [currentKey]: 1, [pageSizeKey]: 10 }] }, otherOptions)

  const { data, params, run, ...rest } = request<Data, P>(service, finallyOptions)

  const paging = (paginationParams: Record<string, number>) => {
    const [oldPaginationParams, ...restParams] = (params.value as P[]) || []
    const newPaginationParams = { ...oldPaginationParams, ...paginationParams }
    const mergerParams = [newPaginationParams, ...restParams] as P
    run(...mergerParams)
  }

  const changeCurrent = (current: number) => {
    paging({ [currentKey]: current })
  }

  const changePageSize = (pageSize: number) => {
    paging({ [pageSizeKey]: pageSize })
  }

  const changePagination = (current: number, pageSize: number) => {
    paging({ [currentKey]: current, [pageSizeKey]: pageSize })
  }

  const total = computed<number>(() => get(data.value, totalKey, 0))

  const current = computed({
    get: () => {
      return params.value?.[0]?.[currentKey] || finallyOptions.defaultParams[0][currentKey]
    },
    set: (val: number) => {
      changeCurrent(val)
    }
  })

  const pageSize = computed({
    get: () => {
      return params.value?.[0]?.[pageSizeKey] || finallyOptions.defaultParams[0][pageSizeKey]
    },
    set: (val: number) => {
      changePageSize(val)
    }
  })

  const totalPage = computed(() => get(data.value, totalPageKey, Math.ceil(total.value / pageSize.value)))

  return {
    data,
    params,
    current,
    pageSize,
    total,
    totalPage,
    run,
    changeCurrent,
    changePageSize,
    changePagination,
    ...rest
  }
}

function usePagination<Data, P extends unknown[] = any[]>(
  service: Service<ResponseData<Data>, P>,
  options?: PaginationOptions<ResponseData<Data>, P>
): PaginationFetchResult<ResponseData<Data>, P> {
  return pagination(service, options)
}

export default usePagination
